let _Vue = null

export default class VueRouter {
  // 参数：Vue 构造函数 可选参数： 选项对象
  static install (Vue) {
    // 1. 判断当前插件是否已经被安装
    if (VueRouter.install.installed) {
      return
    }
    VueRouter.install.installed = true

    // 2. 把Vue构造函数记录到全局变量 (将来在vue-router的实例方法中需要使用Vue构造函数，创建router-link， router-view组件)
    _Vue = Vue

    // 3. 把创建Vue实例时候传入的router对象注入到Vue实例上
    // 静态方法内this指VueRouter，不是vue实例，解决：使用混入注册
    // _Vue.prototype.$router = this.$options.router

    // 混入(全局)
    _Vue.mixin({
      beforeCreate () {
        // 内部this指vue实例，实例this可以获取到，获取不到el， data，props
        // 只有注入了router的才进入if
        if (this.$options.router) {
          // 把注入的router放在vue实例原型上，外面可以通过this.$router使用VueRouter
          _Vue.prototype.$router = this.$options.router
          // 对注入实例中的router初始化
          this.$options.router.init()
        }
      }
    })
  }

  constructor (options) {
    this.options = options
    this.routeMap = {} // 将options中的routes解析出来
    this.data = _Vue.observable({
      current: '/' // 默认是/
    }) // 响应式对象
  }

  init () {
    this.createRouteMap()
    this.initComponents(_Vue)
    this.initEvent()
  }

  createRouteMap () {
    // 遍历所有路由规则，解析成键值对，存入routeMap对象中
    this.options.routes.forEach(route => {
      this.routeMap[route.path] = route.component
    })
  }

  initComponents (Vue) {
    // <router-link to="/about">About</router-link>
    // 内部this指组件
    Vue.component('router-link', {
      props: {
        to: String
      },

      // 如果用template，只能使用完整编译，通过配置 vue.config.js  module.exports={ runtimeCompiler:true }
      // template: `<a :href="to"><slot></slot></a>`,

      render (h) {
        return h('a', {
          attrs: {
            href: this.to
          },
          on: {
            // 对路由的点击进行处理，阻止每次点击就向服务器发请求，阻止默认行为
            // 实现前端路由
            click: this.clickHandler
          }
        }, this.$slots.default)
      },
      methods: {
        clickHandler (e) {
          // h5 history模式 只修改地址栏，不向服务器提交请求
          // https://developer.mozilla.org/zh-CN/docs/Web/API/History_API#pushstate_%E6%96%B9%E6%B3%95
          history.pushState(null, null, this.to)

          // 加载跳转路径的对应组件
          // 修改响应式对象会重新出发 router-view 的更新
          // this指vue组件，此时组件属于vue，vue原型上已注入$router
          this.$router.data.current = this.to

          // hash模式修改
          window.location.hash = "#"+this.to
          this.$router.data.current = this.to

          // 阻止默认行为
          e.preventDefault()
        }
      }
    })

    const self = this
    Vue.component('router-view', {
      render (h) {
        // 获取当前路由地址
        // 根据当前路由地址获取对应路由组件
        // 将路由组件转化成 VNode(通过h函数)
        // console.log('self1', self === this.$router) // true
        // const component = self.routeMap[self.data.current]
        const component = this.$router.routeMap[this.$router.data.current]
        return h(component)
      }
    })
  }

  initEvent () {
    // 处理history 前进后退
    window.addEventListener('popstate', () => {
      this.data.current = window.location.pathname
    })
    // 处理hash 
    window.addEventListener('hashChange', () => {
      this.data.current = window.location.hash
    })
  }
}
